#include "cqtopencvviewergl.h"


CQtOpenCVViewerGl::CQtOpenCVViewerGl(QWidget *parent) :
QOpenGLWidget(parent)
{
    mBgColor = QColor::fromRgb(150, 150, 150);
	setUpdatesEnabled(true);
}

void CQtOpenCVViewerGl::initializeGL()
{
    makeCurrent();
    initializeOpenGLFunctions();

    float r = ((float)mBgColor.darker().red())/255.0f;
    float g = ((float)mBgColor.darker().green())/255.0f;
    float b = ((float)mBgColor.darker().blue())/255.0f;
    glClearColor(r,g,b,1.0f);
}

void CQtOpenCVViewerGl::resizeGL(int width, int height)
{
    makeCurrent();
    glViewport(0, 0, (GLint)width, (GLint)height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho(0, width, -height, 0, 0, 1);

    glMatrixMode(GL_MODELVIEW);

    recalculatePosition();

    emit imageSizeChanged(mRenderWidth, mRenderHeight);

    updateScene();
}

void CQtOpenCVViewerGl::updateScene()
{
    if (this->isVisible()) update();
}

void CQtOpenCVViewerGl::paintGL()
{
    makeCurrent();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    renderImage();
}

void CQtOpenCVViewerGl::renderImage()
{

	drawMutex.lock();
    makeCurrent();

    glClear(GL_COLOR_BUFFER_BIT);

    if (!mRenderQtImg.isNull())
    {
        glLoadIdentity();

        glPushMatrix();
        {
			//std::chrono::time_point<std::chrono::high_resolution_clock> TimeStart( std::chrono::high_resolution_clock::now() );
            if (mResizedImg.width() <= 0)
            {
                if (mRenderWidth == mRenderQtImg.width() && mRenderHeight == mRenderQtImg.height())
                    mResizedImg = mRenderQtImg;
                else
				{
					//std::chrono::time_point<std::chrono::high_resolution_clock> TimeStart( std::chrono::high_resolution_clock::now() );
                    mResizedImg = mRenderQtImg.scaled(QSize(mRenderWidth, mRenderHeight),
                                                      Qt::IgnoreAspectRatio,
                                                      Qt::SmoothTransformation);

					//syslog(SYSLOG_ERR, (std::string("scaled:")+
					//	std::to_string(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() -TimeStart).count())+" us"  ).c_str()) ;
				}
            }
			//syslog(SYSLOG_ERR, (std::string("renderImage:")+
			//	std::to_string(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() -TimeStart).count())+" us" ).c_str()) ;


            // ---> Centering image in draw area

            glRasterPos2i(mRenderPosX, mRenderPosY);

            glPixelZoom(1, -1);
            //glDrawPixels(mResizedImg.width(), mResizedImg.height(), GL_RGBA, GL_UNSIGNED_BYTE, mResizedImg.bits());
			glDrawPixels(mResizedImg.width(), mResizedImg.height(), GL_RGBA, GL_UNSIGNED_BYTE, mResizedImg.bits());
			
        }
        glPopMatrix();

        // end
        glFlush();
    }

	drawMutex.unlock();
}

void CQtOpenCVViewerGl::recalculatePosition()
{
	mImgRatio = 1;
	if(mOrigImage.empty())
	{
		if(!mRenderQtImg.isNull())
		{
			mImgRatio = (float)mRenderQtImg.width()/(float)mRenderQtImg.height();
		}		
	}
	else
	{
		mImgRatio = (float)mOrigImage.cols/(float)mOrigImage.rows;
	}

    mRenderWidth = this->size().width();
    mRenderHeight = floor(mRenderWidth / mImgRatio);

    if (mRenderHeight > this->size().height())
    {
        mRenderHeight = this->size().height();
        mRenderWidth = floor(mRenderHeight * mImgRatio);
    }

    mRenderPosX = floor((this->size().width() - mRenderWidth) / 2);
    mRenderPosY = -floor((this->size().height() - mRenderHeight) / 2);

    mResizedImg = QImage();
}

bool CQtOpenCVViewerGl::showImage(const cv::Mat& image)
{
	drawMutex.lock();
	    		
	if (image.channels() == 3)
        cvtColor(image, mOrigImage, CV_BGR2RGBA);
    else if (image.channels() == 1)
        cvtColor(image, mOrigImage, CV_GRAY2RGBA);
	else if (image.channels() == 4)
		mOrigImage = image;
    else return false;

	if(!mResizedImg.isNull())
	{
		//std::chrono::time_point<std::chrono::high_resolution_clock> TimeStart( std::chrono::high_resolution_clock::now() );
		cv::resize(mOrigImage, mOrigImage,cv::Size(mResizedImg.width(),mResizedImg.height()));
		/*syslog(SYSLOG_ERR, (std::string("cv::resize:")+
			std::to_string(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() -TimeStart).count())+" us"  ).c_str()) ;*/
	}

    mRenderQtImg = QImage((const unsigned char*)(mOrigImage.data),
                          mOrigImage.cols, mOrigImage.rows,
                          mOrigImage.step1(), QImage::Format_RGB32);
    recalculatePosition();

    updateScene();
	drawMutex.unlock();
    return true;
}

bool CQtOpenCVViewerGl::showImage(const QImage& image)
{
	drawMutex.lock();
	if( image.isNull() )
	{
		return false;
	}

	mRenderQtImg = image;

	recalculatePosition();

	updateScene();
	drawMutex.unlock();
	return true;
}

#include "moc_cqtopencvviewergl.cpp"
